﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GraphCompiler.Core.SyntaxRepresentation;

namespace GraphCompiler.Core.Parsing
{
    public abstract class ParserBase<T> : ITypedParser<T>
        where T : SyntaxNode
    {
        List<IParser> _childParsers = new List<IParser>();
        protected TokenCollection _tokens = new TokenCollection();
        
        // Possible substates

        public abstract T ParseTypedNode(TokenCollection tokens);

        public virtual SyntaxNode Parse(TokenCollection tokens)
        {
            return ParseTypedNode(tokens);
        }

        protected IEnumerable<SyntaxNode> ParseChildElements()
        {
            bool wasSomethingParsed = true;

            while (!_tokens.IsNextTokenClosingBracket && wasSomethingParsed)
            {
                wasSomethingParsed = false;

                foreach (var parser in _childParsers)
                {
                    if (parser.IsApplicable(_tokens))
                    {
                        yield return parser.Parse(_tokens);
                        wasSomethingParsed = true;
                    }
                }
            }
        }

        protected void ParseAndAddChildElements()
        {
            var childNodes = ParseChildElements();

            foreach (var childNode in childNodes)
                Node.AddChild(childNode);
        }

        protected SyntaxNode Node { get; set; }

        public IEnumerable<IParser> ChildParsers
        {
            get
            {
                return _childParsers;
            }
        }

        protected void AddChildParser(IParser parser)
        {
            _childParsers.Add(parser);
        }

        protected void ConsumeToken(string expectedTokenString)
        {
            _tokens.ConsumeNext(expectedTokenString);
        }

        protected Token ReadToken()
        {
            return _tokens.ReadNext();
        }

        protected bool IsTokenListEmpty
        {
            get
            {
                return _tokens.IsEmpty;
            }
        }

        public abstract bool IsApplicable(TokenCollection tokens);
    }
}
